//------------------------------------------------------------------------------
//	file sm-auto.cpp
//	brief
//		state machine auto test
//
//		In this test, the state machine is advanced automatically based
//		on two inputs: (1) the current state (2) the current event.
//		The table sm_auto  contains all possible combinations of these
//		two variables.  Using current state and event, the next state
//		is "automatically" located.  The code in each function can focus on
//		processing the state and not worry about managing the state.
//
//	$Id: sm-auto.cpp 230 2014-01-05 10:47:22Z ac.verbeck@gmail.com $
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
//	Copyright and Disclaimer Notice
//
//	Copyright (c) 2012 A.C. Verbeck
//
//	This file is part of SM: A State Machine Library.
//
//	SM is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	SM is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with SM.  If not, see <http://www.gnu.org/licenses/>.
//
//------------------------------------------------------------------------------
#include <stdio.h>
#include <stdint.h>									//	Standard int types
#include <stdbool.h>								//	Bool

#include "sm.h"
#include "debug.h"

//----------------------------------------------------------------------------
// Local enum
//----------------------------------------------------------------------------
enum {ST_STANDBY, ST_RUN, ST_MENU, ST_DISPLAY, ST_CT	};
enum {EV_POWER, EV_MENU, EV_DISPLAY, EV_BUTTON, EV_CT	};

//----------------------------------------------------------------------------
// Local functions
//----------------------------------------------------------------------------
static SM_STATUS s0_st_enter(void);
static SM_STATUS s0_st_process(SM_EVENT ev);
static SM_STATUS s0_st_exit(void);

static SM_STATUS s1_st_enter(void);
static SM_STATUS s1_st_process(SM_EVENT ev);
static SM_STATUS s1_st_exit(void);

static SM_STATUS s2_st_enter(void);
static SM_STATUS s2_st_process(SM_EVENT ev);
static SM_STATUS s2_st_exit(void);

static SM_STATUS s3_st_enter(void);
static SM_STATUS s3_st_process(SM_EVENT ev);
static SM_STATUS s3_st_exit(void);

//----------------------------------------------------------------------------
// Local data
//----------------------------------------------------------------------------
static STATE_INIT sm_state_init = {
	ST_STANDBY,
	ST_STANDBY,
	ST_STANDBY
};

static const SM_STATE_FN states[] = {
	[ST_STANDBY]	= {	s0_st_enter,	s0_st_process,		s0_st_exit		},	//	state: s0 -- standby state
	[ST_RUN]		= {	s1_st_enter,	s1_st_process,		s1_st_exit		},	//	state: s1 -- run state
	[ST_MENU]		= {	s2_st_enter,	s2_st_process,		s2_st_exit		},	//	state: s2 -- menu state
	[ST_DISPLAY]	= {	s3_st_enter,	s3_st_process,		s3_st_exit		},	//	state: s3 -- display state
};
static const uint32_t sm_state_ct = sizeof(states)/sizeof(SM_STATE_FN);

static const SM_STATE sm_auto[ST_CT][EV_CT] = {
//						EV_POWER			EV_MENU				EV_DISPLAY			EV_BUTTON
	[ST_STANDBY]	= {	ST_RUN,				ST_STANDBY,			ST_STANDBY,			ST_STANDBY	},
	[ST_RUN]		= {	ST_STANDBY,			ST_MENU,			ST_DISPLAY,			ST_RUN		},
	[ST_MENU]		= {	ST_STANDBY,	   		ST_RUN,				ST_DISPLAY,			ST_MENU		},
	[ST_DISPLAY]	= {	ST_STANDBY,			ST_MENU,			ST_RUN,				ST_DISPLAY	},
//						EV_POWER			EV_MENU				EV_DISPLAY			EV_BUTTON
};

static SM state_m(states, sm_state_ct, &sm_state_init);

//------------------------------------------------------------------------------
//	brief
//		Next test state machine
//		Run the state machine -- process incoming events
//
//	param
//		int ev:	incoming event
//
//	return
//		none
//------------------------------------------------------------------------------
void sm_auto_process(int ev_in)
{
	int ev_proc;
	SM_STATE curr_state;

	switch (ev_in) {
	case 'p':
		ev_proc = EV_POWER;
		break;																	//	p = power event
	case 'm':
		ev_proc = EV_MENU;
		break;																	//	m = menu event
	case 'd':
		ev_proc = EV_DISPLAY;
		break;																	//	d = display event
	default:
		ev_proc = EV_BUTTON;
		break;																	//	default is button
	}

	curr_state = state_m.GetState();											//	Get current state
	state_m.StateChange(sm_auto[curr_state][ev_proc]);							//	update to new state based on table
	state_m.Process((SM_EVENT)ev_in);											//	Process current state then, go to auto state
}

//------------------------------------------------------------------------------
//	brief
//		State machine state processing
//		S0 state processing: This is the standby state.
//		- s0_st_enter:		enter state
//		- s0_st_process:	process state
//		- s0_st_exit:		exit state
//
//	param
//		sm:	state machine
//		ev:	state machine event
//
//	return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s0_st_enter(void)
{
	TRACE(INFO,"standby enter");												//	Display state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s0_st_process(SM_EVENT ev)
{
	TRACE(INFO,"standby process");												//	Display state processing
	return SM_OK;																//	Status is OK
}
static SM_STATUS s0_st_exit(void)
{
	TRACE(INFO,"standby exit");													//	Display state exit
	return SM_OK;																//	Status is OK
}

//------------------------------------------------------------------------------
//	brief
//		State machine state processing
//		S1 state processing: This is the run state.
//		- s1_st_enter:		enter state
//		- s1_st_process:	process state
//		- s1_st_exit:		exit state
//
//	param
//		ev:	state machine event
//
//	return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s1_st_enter(void)
{
	TRACE(INFO,"run enter");													//	Display state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s1_st_process(SM_EVENT ev)
{
	TRACE(INFO,"run process");													//	Display state processing
	return SM_OK;																//	Status is OK
}
static SM_STATUS s1_st_exit(void)
{
	TRACE(INFO,"run exit");														//	Display state exit
	return SM_OK;																//	Status is OK
}

//------------------------------------------------------------------------------
//	brief
//		State machine state processing
//		S2 state processing: This is the menu state.
//		- s2_st_enter:		enter state
//		- s2_st_process:	process state
//		- s2_st_exit:		exit state
//
//	param
//		ev:	state machine event
//
//	return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s2_st_enter(void)
{
	TRACE(INFO,"menu enter");													//	Display state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s2_st_process(SM_EVENT ev)
{
	TRACE(INFO,"menu process");													//	Display state exit
	return SM_OK;																//	Status is OK
}
static SM_STATUS s2_st_exit(void)
{
	TRACE(INFO,"menu exit");													//	Display state exit
	return SM_OK;																//	Status is OK
}

//------------------------------------------------------------------------------
//	brief
//		State machine state processing
//		S3 state processing: This is the display state.
//		- s3_st_enter:		enter state
//		- s3_st_process:	process state
//		- s3_st_exit:		exit state
//
//	param
//		ev:	state machine event
//
//	return
//		state machine status
//------------------------------------------------------------------------------
static SM_STATUS s3_st_enter(void)
{
	TRACE(INFO,"display enter");												//	Display state entry
	return SM_OK;																//	Status is OK
}
static SM_STATUS s3_st_process(SM_EVENT ev)
{
	TRACE(INFO,"display process");												//	Display state exit
	return SM_OK;																//	Status is OK
}
static SM_STATUS s3_st_exit(void)
{
	TRACE(INFO,"display exit");													//	Display state exit
	return SM_OK;																//	Status is OK
}

//
//  End: sm-auto.cpp
//
